#include "Bullet.h"
#include "GameScene.h"
#include "Player.h"
#include "Game.h"
#include "TextureLoader.h"

Bullet::Bullet(float x, float y, int w, int h, Angle angle, float speed, GameScene *scene, bool isEnemyBullet)
    : MoveObject(x, y, w, h, angle, speed), isEnemyBullet_(isEnemyBullet), scene_(scene)
{
}

void Bullet::Update(float dt)
{
    Move(dt);
    auto player_bullet = scene_->GetPlayer()->GetBullet();
    checkBulletWithTerrain();
    if(isAlive_)
    {
        checkBulletWithTank();
        if(isAlive_ && player_bullet)
        {
            checkBulletWithBullet();
        }
    }
}

void Bullet::Render()
{
    auto renderer = Game::GetInstance().GetRenderer();
    auto texture = TextureLoader::Instance().GetBulletTexture(angle_);
    SDL_RenderCopy(renderer, texture.first, &texture.second, &GetRect());
}

void Bullet::Move(float dt)
{
    switch (angle_)
    {
    case Angle::LEFT:
        x_ = x_ - speed_ * dt;
        break;
    case Angle::RIGHT:
        x_ = x_ + speed_ * dt;
        break;
    case Angle::UP:
        y_ = y_ - speed_ * dt;
        break;
    case Angle::DOWN:
        y_ = y_ + speed_ * dt;
        break;
    default:
        break;
    }
}

void Bullet::checkBulletWithTerrain()
{
    int x = static_cast<int>(x_);
    int y = static_cast<int>(y_);

    SDL_Rect bulletRect = GetRect();
    SDL_Point vertexPos[2];
    Terrain* terrain[2];
    bool isRow = false;
    switch (angle_)
    {
    case Angle::UP:
        isRow = true;
        vertexPos[0] = {x,y};
        vertexPos[1] = {x + width_, y};
        break;
    case Angle::DOWN:
        isRow = true;
        vertexPos[0] = {x, y + height_};
        vertexPos[1] = {x + width_, y + height_};
        break;
    case Angle::LEFT:
        vertexPos[0] = {x, y};
        vertexPos[1] = {x, y + height_};
        break;
    case Angle::RIGHT:
        vertexPos[0] = {x + width_, y};
        vertexPos[1] = {x + width_, y + height_};
        break;
    default:
        break;
    }
    terrain[0] = scene_->GetTerrain(vertexPos[0].x, vertexPos[0].y);
    terrain[1] = scene_->GetTerrain(vertexPos[1].x, vertexPos[1].y);

    if (terrain[0] && terrain[1])
    {
        for (int i = 0; i < 2; i++)
        {
            SDL_Point offset;
            offset = {vertexPos[i].x % MAP_BLOCK_WIDTH, vertexPos[i].y % MAP_BLOCK_HEIGHT};
            SDL_Point piecePos;
            piecePos = {offset.x / MAP_BLOCK_PIECE_SIZE, offset.y / MAP_BLOCK_PIECE_SIZE};
            uint16_t bit = 0x8000 >> (piecePos.x + piecePos.y * 4);

            switch (terrain[i]->type)
            {
            case TerrainType::Iron:
            {
                if(bit & terrain[i]->block_bit)
                {
                    isAlive_ = false;
                }
            }
            break;
            case TerrainType::Brick:
            {
                if(bit & terrain[i]->block_bit)
                {
                    if(isRow)
                    {
                        bit |= i? (bit >> 1) : (bit << 1);
                    }
                    else
                    {
                        bit |= i? (bit >> 4) : (bit << 4);
                    }
                    terrain[i]->block_bit &= ~bit;
                    if(terrain[i]->block_bit == 0)
                    {
                        terrain[i]->type = TerrainType::Empty;
                    }
                    isAlive_ = false;
                }
            }
                break;
            default:
                break;
            }
        }
    }
    else
    {
        isAlive_ = false;
    }
}

void Bullet::checkBulletWithBullet()
{
    if(isEnemyBullet_)
    {
        //处理与玩家子弹间的碰撞
        auto player_bullet = scene_->GetPlayer()->GetBullet();
        if(SDL_HasIntersection(&GetRect(), &player_bullet->GetRect()))
        {
            //处理碰撞
            isAlive_ = false;
            player_bullet->isAlive_ = false;
        }
    }
}

void Bullet::checkBulletWithTank()
{
    if(isEnemyBullet_)
    {
        //检测与玩家之间的碰撞
        auto player = scene_->GetPlayer();
        if(SDL_HasIntersection(&GetRect(), &player->GetRect()))
        {
            isAlive_ = player->isAlive_ = false;
        }
    }
    else
    {
        //检测与敌军坦克间的碰撞
        auto& tanks = scene_->GetTanks();
        for(auto& tank : tanks)
        {
            if(tank->isEnemy())
            {
                if(SDL_HasIntersection(&GetRect(), &tank->GetRect()))
                {
                    isAlive_ = tank->isAlive_ = false;
                }
            }
        }
    }
}
